﻿using ICPFrameLib.Business;
using ICPFrameLib.Attributes;
using XHRPMIS.Common;
using EFFC.Frame.Net.Base.Common;
using EFFC.Frame.Net.Base.Data.Base;
using EFFC.Frame.Net.Module.Extend.EWRA.Attributes;
using EFFC.Frame.Net.Module.Extend.EWRA.Attributes.Validation;
using EFFC.Frame.Net.Unit.DB.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EFFC.Extends.LinqDLR2SQL;
using EFFC.Frame.Net.Unit.DB;
using EFFC.Frame.Net.Base.Data;
using System.IO;
using EFFC.Frame.Net.Base.Constants;
using System.Text.RegularExpressions;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System.Text;
using ICPFrameLib.Common;
using EFFC.Frame.Net.Unit.DB.Datas;

namespace XHRPMIS.Business.v1._0
{
   public partial class MetaDynamicForm
{
    #region OpenAPI
    [EWRARoute("patch", "/md_form/{id}")]
    [EWRAEmptyValid("data")]
    [EWRARouteDesc("修改元数据表中的数据")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("data", "array", @"待修改的数据列表，该数组中的每笔资料必须与ori_data中的下标和栏位都一致，如果为file、picture类型,则需要先进行上传，再传入返回的文件路径，格式:
[
{
    column_name1:'值,
    column_name2:'值,
    .....
    column_nameN:'值,
     _subs:{
        sub_uid1:[{col1:值,col2:值,...colN:值}],
        sub_uid2:[{col1:值,col2:值,...colN:值}],
        .....
        sub_uidN:[{col1:值,col2:值,...colN:值}]
    }
}
]", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("fixed_data_express", "string", @"固定更新数据条件表达式，采用DBExpress的栏位表达式写法，传入时采用base64+urlcode编码方式；
表达式中可以使用一些基础变量，如下：
__login_id:当前登录者ID,
__login_name:当前登录者的登录名称
__user_no:登录信息中的userno值,
__no:登录信息中的no值,
__user_name:登录信息中的username值,
__user_type:登录信息中的usertype值,
__role_no:当前登录者系统角色编号，多个,
__role_name:当前登录者系统角色名称，多个,
__now:当前时间，格式yyyy-MM-dd HH:mm:ss
", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息'
}")]
    public object Update(string id)
    {
        string fixed_data_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.fixed_data_express));
        var fixeddata = parseFixedExpress(fixed_data_express);

        var data = PostDataD.data;
        if (!(data is IEnumerable<object>))
        {
            return new
            {
                code = "failed",
                msg = "参数格式不正确",
            };
        }
        var datalist = ((IEnumerable<object>)data).Select(d => FrameDLRObject.CreateInstance(d)).ToList();
        if (fixeddata != null)
        {
            foreach (var item in datalist)
            {
                foreach (var key in fixeddata.Keys)
                {
                    ((FrameDLRObject)item).SetValue(key, fixeddata.GetValue(key));
                }
            }
        }
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        BeginTrans();
        var rtn = DoPatch(metaup, up, id, datalist, TokenPayLoad.ID, ComFunc.nvl(TokenPayLoad["username"]), ClientInfo.IP, BoolStd.IsNotBoolThen(Configs["Is_UseLocal"]));
        CommitTrans();
        return rtn;
    }
    [EWRARoute("post", "/md_form_mobile/{id}")]
    [EWRAEmptyValid("data")]
    [EWRARouteDesc("修改元数据表中的数据-适用于移动端不能使用patch环境")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("data", "array", @"待修改的数据列表，该数组中的每笔资料必须与ori_data中的下标和栏位都一致，如果为file、picture类型,则需要先进行上传，再传入返回的文件路径，格式:
[
{
    column_name1:'值,
    column_name2:'值,
    .....
    column_nameN:'值,
     _subs:{
        sub_uid1:[{col1:值,col2:值,...colN:值}],
        sub_uid2:[{col1:值,col2:值,...colN:值}],
        .....
        sub_uidN:[{col1:值,col2:值,...colN:值}]
    }
}
]", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("fixed_data_express", "string", @"固定更新数据条件表达式，采用DBExpress的栏位表达式写法，传入时采用base64+urlcode编码方式；
表达式中可以使用一些基础变量，如下：
__login_id:当前登录者ID,
__login_name:当前登录者的登录名称
__user_no:登录信息中的userno值,
__no:登录信息中的no值,
__user_name:登录信息中的username值,
__user_type:登录信息中的usertype值,
__role_no:当前登录者系统角色编号，多个,
__role_name:当前登录者系统角色名称，多个,
__now:当前时间，格式yyyy-MM-dd HH:mm:ss
", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息'
}")]
    public object Update4Mobile(string id)
    {
        string fixed_data_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.fixed_data_express));
        var fixeddata = parseFixedExpress(fixed_data_express);

        var data = PostDataD.data;
        if (!(data is IEnumerable<object>))
        {
            return new
            {
                code = "failed",
                msg = "参数格式不正确",
            };
        }
        var datalist = ((IEnumerable<object>)data).Select(d => FrameDLRObject.CreateInstance(d)).ToList();
        if (fixeddata != null)
        {
            foreach (var item in datalist)
            {
                foreach (var key in fixeddata.Keys)
                {
                    ((FrameDLRObject)item).SetValue(key, fixeddata.GetValue(key));
                }
            }
        }
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        BeginTrans();
        var rtn = DoPatch(metaup, up, id, datalist, TokenPayLoad.ID, ComFunc.nvl(TokenPayLoad["username"]), ClientInfo.IP, BoolStd.IsNotBoolThen(Configs["Is_UseLocal"]));
        CommitTrans();
        return rtn;
    }
    [EWRARoute("patch", "/md_form/{id}/{pk}")]
    [EWRAEmptyValid("data")]
    [EWRARouteDesc("修改元数据表中的指定数据")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("pk", "string", @"待删除的数据的_default_pk值", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("data", "array", @"待修改的数据，格式:
{
    column_name1:'值,
    column_name2:'值,
    .....
    column_nameN:'值,
     _subs:{
        sub_uid1:[{col1:值,col2:值,...colN:值}],
        sub_uid2:[{col1:值,col2:值,...colN:值}],
        .....
        sub_uidN:[{col1:值,col2:值,...colN:值}]
    }
}", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("fixed_data_express", "string", @"固定更新数据条件表达式，采用DBExpress的栏位表达式写法，传入时采用base64+urlcode编码方式；
表达式中可以使用一些基础变量，如下：
__login_id:当前登录者ID,
__login_name:当前登录者的登录名称
__user_no:登录信息中的userno值,
__no:登录信息中的no值,
__user_name:登录信息中的username值,
__user_type:登录信息中的usertype值,
__role_no:当前登录者系统角色编号，多个,
__role_name:当前登录者系统角色名称，多个,
__now:当前时间，格式yyyy-MM-dd HH:mm:ss
", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息'
}")]
    public object Update(string id, string pk)
    {
        string fixed_data_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.fixed_data_express));
        var fixeddata = parseFixedExpress(fixed_data_express);
        var data = FrameDLRObject.CreateInstance(PostDataD.data);
        if (fixeddata != null)
        {
            foreach (var key in fixeddata.Keys)
            {
                ((FrameDLRObject)data).SetValue(key, fixeddata.GetValue(key));
            }
        }
        data._default_pk = pk;

        var datalist = new List<object>();
        datalist.Add(data);

        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        BeginTrans();
        var rtn = DoPatch(metaup, up, id, datalist, TokenPayLoad.ID, ComFunc.nvl(TokenPayLoad["username"]), ClientInfo.IP, BoolStd.IsNotBoolThen(Configs["Is_UseLocal"]));
        CommitTrans();
        return rtn;
    }
    [EWRARoute("post", "/md_form_mobile/{id}/{pk}")]
    [EWRAEmptyValid("data")]
    [EWRARouteDesc("修改元数据表中的指定数据-适用于移动端不能使用patch环境")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("pk", "string", @"待删除的数据的_default_pk值", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("data", "array", @"待修改的数据，格式:
{
    column_name1:'值,
    column_name2:'值,
    .....
    column_nameN:'值,
     _subs:{
        sub_uid1:[{col1:值,col2:值,...colN:值}],
        sub_uid2:[{col1:值,col2:值,...colN:值}],
        .....
        sub_uidN:[{col1:值,col2:值,...colN:值}]
    }
}", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("fixed_data_express", "string", @"固定更新数据条件表达式，采用DBExpress的栏位表达式写法，传入时采用base64+urlcode编码方式；
表达式中可以使用一些基础变量，如下：
__login_id:当前登录者ID,
__login_name:当前登录者的登录名称
__user_no:登录信息中的userno值,
__no:登录信息中的no值,
__user_name:登录信息中的username值,
__user_type:登录信息中的usertype值,
__role_no:当前登录者系统角色编号，多个,
__role_name:当前登录者系统角色名称，多个,
__now:当前时间，格式yyyy-MM-dd HH:mm:ss
", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息'
}")]
    public object Update4Mobile(string id, string pk)
    {
        string fixed_data_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.fixed_data_express));
        var fixeddata = parseFixedExpress(fixed_data_express);
        var data = FrameDLRObject.CreateInstance(PostDataD.data);
        if (fixeddata != null)
        {
            foreach (var key in fixeddata.Keys)
            {
                ((FrameDLRObject)data).SetValue(key, fixeddata.GetValue(key));
            }
        }
        data._default_pk = pk;

        var datalist = new List<object>();
        datalist.Add(data);

        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        BeginTrans();
        var rtn = DoPatch(metaup, up, id, datalist, TokenPayLoad.ID, ComFunc.nvl(TokenPayLoad["username"]), ClientInfo.IP, BoolStd.IsNotBoolThen(Configs["Is_UseLocal"]));
        CommitTrans();
        return rtn;
    }
    #endregion

    #region LocalFunction
    public object DoPatch(UnitParameter metaup, UnitParameter up, string id, IEnumerable<object> data,
        string login_id = "", string login_name = "", string login_ip = "", bool is_use_local_upload = true)
    {
        var datalist = data.Select((p) =>
        {
            var dobj = FrameDLRObject.CreateInstance(p, FrameDLRFlags.SensitiveCase);
            dobj.Remove("RowNumber");
            dobj.Remove("add_id");
            dobj.Remove("add_name");
            dobj.Remove("add_ip");
            dobj.Remove("add_time");
            dobj.Remove("last_id");
            dobj.Remove("last_name");
            dobj.Remove("last_ip");
            dobj.Remove("last_time");
            return dobj;
        }).ToList();

        var info = MetaDataUtilities.GetAllTables(metaup).Where(w => (w.MetaUID == id || w.MetaName == id) && w.IsCreated).FirstOrDefault();
        if (info == null)
        {
            return new
            {
                code = "failed",
                msg = "元数据表不存在",
            };
        }
        string tablename = info.MetaName;
        string metauid = info.MetaUID;
        //查看当前资料是否已经完成或终止
        var pks = string.Join(",", datalist.Select(d => ComFunc.nvl(d.GetValue("_default_pk"))));
        var existlist = (from t in DB.LamdaTable(up, tablename, "a")
                         where t._default_pk.within(pks)
                         select t).GetQueryList(up);
        if (existlist.Where(w => IntStd.IsNotIntThen(w._lock) == MetaLock.Lock
       || IntStd.IsNotIntThen(w._lock) == MetaLock.LockUpdate
       || IntStd.IsNotIntThen(w._lock) == MetaLock.LockUpdateDelete).Count() > 0)
        {
            return new
            {
                code = "failed",
                msg = "存在已锁定的资料，不可继续操作",
            };
        }
        //目前系统支持的数据类型及相关约束
        var support_data_type = MetaDataUtilities.GetAllDataType(metaup);
        var auto_fix_datatype = support_data_type.Where(w => w.IsAutoFix);
        var auto_fix_string = auto_fix_datatype.Select(d => d.DataType).ToArray();
        //从表集
        var subs = MetaDataUtilities.GetAllTables(metaup).Where(w => w.MetaMainUID == info.MetaUID && w.IsCreated).ToList();
        var sub_dic = subs.ToDictionary(k => k.MetaUID, v => v.MetaName);
        var sub_dic_name2uid = subs.ToDictionary(k => k.MetaName, v => v.MetaUID);
        datalist = data.Select((p) =>
        {
            var dobj = FrameDLRObject.CreateInstance(p, FrameDLRFlags.SensitiveCase);
            if (dobj._subs != null)
            {
                FrameDLRObject subs = FrameDLRObject.CreateInstance(dobj._subs, FrameDLRFlags.SensitiveCase);
                foreach (var k in subs.Keys)
                {
                    if (sub_dic_name2uid.ContainsKey(k))
                    {
                        var v = subs.GetValue(k);
                        subs.Remove(k);
                        subs.SetValue(sub_dic_name2uid[k], v);
                    }
                }
                dobj._subs = subs;
            }
            return dobj;
        }).ToList();
        //固定columns
        var fixed_columns = MetaDataUtilities.FixColumnsModel;

        var columns = info.columns.Where(w => !w.IsVirsual).ToList();
        columns.AddRange(fixed_columns);
        //虚拟栏位
        var virsual_columns = info.columns.Where(w => w.IsVirsual).ToList();

        var sub_uids = subs.Select(d => d.MetaUID).ToList();
        var subcolumnslist = MetaDataUtilities.GetAllColumns(metaup).Where(w => !w.IsVirsual && sub_uids.Contains(w.MetaUID)).ToList();
        //虚拟栏位
        var virsual_subcolumnslist = MetaDataUtilities.GetAllColumns(metaup).Where(w => w.IsVirsual && sub_uids.Contains(w.MetaUID)).ToList();

        var subcolumnslist2 = (from t in subcolumnslist
                               group t by t.MetaUID into g
                               select new
                               {
                                   metauid = ComFunc.nvl(g.First().MetaUID),
                                   columns = g.Select(gd =>
                                   {
                                       var dobj = gd;
                                       return gd;
                                   }).Concat(fixed_columns).ToList()
                               }).ToList();
        var sub_columns = (from t in subcolumnslist2
                           select new
                           {
                               t.metauid,
                               t.columns,
                               auto_fix_columns = t.columns.Where(gd => auto_fix_string.Contains((string)ComFunc.nvl(gd.MetaDataType))).Select(ss =>
                               {
                                   return new
                                   {
                                       column_name = ss.MetaColumnName,
                                       data_type = ss.MetaDataType,
                                       is_allow_empty = ss.MetaAllowEmpty,
                                       precision = IntStd.IsNotIntThen(ss.MetaDataPrecision.HasValue ? ss.MetaDataPrecision.Value : 0, 0),
                                       format = ss.MetaFormat
                                   };
                               }).ToList(),
                               notemptycolumns = t.columns.Where(p => !p.MetaAllowEmpty).Select((p) =>
                               {
                                   return new
                                   {
                                       column_name = p.MetaColumnName,
                                       column_desc = p.MetaColumnDesc
                                   };
                               }).ToList()
                           }).ToList();

        var column_names = columns.Select((p) => p.MetaColumnName).ToList();
        var column_int = columns.Where(w => w.Map_DBType == "int").Select((p) => p.MetaColumnName).ToList();
        var column_numbric = columns.Where(w => w.Map_DBType == "numberic").Select((p) => p.MetaColumnName).ToList();
        var column_bit = columns.Where(w => w.Map_DBType == "bit").Select((p) => p.MetaColumnName).ToList();
        var column_datetime = columns.Where(w => new string[] { "datetime", "date" }.Contains(w.MetaDataType) && w.MetaDataType == "datetime").Select((p) => p.MetaColumnName).ToList();
        var column_time = columns.Where(w => ComFunc.nvl(w.MetaDataType) == "time" && ComFunc.nvl(w.MetaDataType) == "datetime").Select((p) => p.MetaColumnName).ToList();
        var column_date_year_month = columns.Where(w => ComFunc.nvl(w.MetaDataType) == "date_year_month" && ComFunc.nvl(w.Map_DBType) == "datetime").Select((p) => p.MetaColumnName).ToList();
        var column_date_year = columns.Where(w => ComFunc.nvl(w.MetaDataType) == "date_year" && ComFunc.nvl(w.Map_DBType) == "datetime").Select((p) => p.MetaColumnName).ToList();
        var notemptycolumns = columns.Where(p => !BoolStd.IsNotBoolThen(p.MetaAllowEmpty, true)).Select((p) =>
        {
            return new
            {
                column_name = p.MetaColumnName,
                column_desc = p.MetaColumnDesc
            };
        }).ToList();
        //系统自动填入参数的栏位
        var auto_fix_columns = columns.Where(p => auto_fix_string.Contains((string)ComFunc.nvl(p.MetaDataType))).Select((p) =>
        {
            return new
            {
                column_name = p.MetaColumnName,
                data_type = p.MetaDataType,
                is_allow_empty = p.MetaAllowEmpty,
                precision = IntStd.IsNotIntThen(p.MetaDataPrecision.HasValue ? p.MetaDataPrecision.Value : 0, 0),
                format = p.MetaFormat
            };
        }).ToList();
        var pkcolumns = columns.Where(p => p.MetaIsPK && p.MetaDataType != "text").Select((p) => p.MetaColumnName).ToList();
        var logicuniquecolumns = columns.Where(p => p.MetaLogicUnique && p.MetaDataType != "text").Select((p) => p.MetaColumnName).ToList();
        //虚拟栏位
        var virsual_column_names = virsual_columns.Select((p) => p.MetaColumnName).ToList();
        var virsual_subcolumn_names = virsual_subcolumnslist.Select((p) => p.MetaColumnName).ToList();
        //subs数据格式检查
        foreach (FrameDLRObject d in datalist)
        {
            if (d.GetValue("_subs") != null)
            {
                FrameDLRObject tsubs = FrameDLRObject.CreateInstance(d.GetValue("_subs"));
                foreach (var key in tsubs.Keys)
                {
                    if (!(tsubs.GetValue(key) is IEnumerable<object>))
                    {
                        return new
                        {
                            code = "failed",
                            msg = "从表的数据格式不正确"
                        };
                    }
                    if (!sub_dic.ContainsKey(key))
                    {
                        return new
                        {
                            code = "failed",
                            msg = "从表与主表关系不正确"
                        };
                    }
                    var tl = ((IEnumerable<object>)tsubs.GetValue(key)).Select(dd => FrameDLRObject.CreateInstance(dd, FrameDLRFlags.SensitiveCase)).ToList();
                    tsubs.SetValue(key, tl);
                }
            }
        }
        // 移除虚拟栏位
        foreach (FrameDLRObject d in datalist)
        {
            foreach (var c in virsual_column_names)
            {
                d.Remove(c);
            }
            if (d.GetValue("_subs") != null)
            {
                FrameDLRObject tsubs = FrameDLRObject.CreateInstance(d.GetValue("_subs"));
                foreach (var key in tsubs.Keys)
                {
                    var tl = (IEnumerable<object>)tsubs.GetValue(key);
                    foreach (FrameDLRObject sitem in tl)
                    {
                        foreach (var c in virsual_subcolumn_names)
                        {
                            sitem.Remove(c);
                        }
                    }
                }
            }
        }
        //系统自动填入数据的栏位
        foreach (FrameDLRObject d in datalist)
        {
            foreach (var c in auto_fix_columns)
            {
                if (ComFunc.nvl(d.GetValue(c.column_name)) == ""
                    && !c.is_allow_empty)
                {
                    var dts = auto_fix_datatype.Where(w => w.DataType == c.data_type);
                    if (dts.Count() > 0)
                    {
                        var auto_fix_method = ComFunc.nvl(dts.First().AutoFix_Method);
                        if (auto_fix_method == "AutoCode")
                        {
                            d.SetValue(c.column_name, genAutoCode(up, metauid, c.column_name, ComFunc.nvl(c.format), d));
                        }
                        else
                        {
                            d.SetValue(c.column_name, genAutoFixValue(auto_fix_method, c.precision));
                        }
                    }
                }
            }
            if (d.GetValue("_subs") != null)
            {
                FrameDLRObject tsubs = FrameDLRObject.CreateInstance(d.GetValue("_subs"));
                foreach (var key in tsubs.Keys)
                {
                    var l = (IEnumerable<object>)tsubs.GetValue(key);
                    var sub_tablename = sub_dic[key];
                    foreach (var c in sub_columns.Where(sw => sw.metauid == key).First().auto_fix_columns)
                    {
                        var dts = auto_fix_datatype.Where(w => w.DataType == c.data_type);
                        if (dts.Count() > 0)
                        {
                            var auto_fix_method = ComFunc.nvl(dts.First().AutoFix_Method);
                            if (auto_fix_method == "AutoCode")
                            {
                                foreach (FrameDLRObject sub_data in l)
                                {
                                    if (ComFunc.nvl(sub_data.GetValue(c.column_name)) == ""
                                        && !c.is_allow_empty)
                                    {
                                        sub_data.SetValue(c.column_name, genAutoCode(up, key, c.column_name, ComFunc.nvl(c.format), sub_data));
                                    }
                                }

                            }
                            else
                            {
                                foreach (FrameDLRObject sub_data in l)
                                {
                                    if (ComFunc.nvl(sub_data.GetValue(c.column_name)) == ""
                                        && !c.is_allow_empty)
                                    {
                                        sub_data.SetValue(c.column_name, genAutoFixValue(auto_fix_method, c.precision));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        //栏位检查
        foreach (FrameDLRObject d in datalist)
        {
            foreach (var ne in notemptycolumns)
            {
                if (ComFunc.nvl(d.GetValue(ne.column_name)) == "")
                {
                    return new
                    {
                        code = "failed",
                        msg = $"{ne.column_desc}栏位不可为空",
                    };
                }
            }
            if (d.GetValue("_subs") != null)
            {
                FrameDLRObject tsubs = FrameDLRObject.CreateInstance(d.GetValue("_subs"));
                foreach (var key in tsubs.Keys)
                {
                    var l = (IEnumerable<object>)tsubs.GetValue(key);
                    foreach (var c in sub_columns.Where(ww => ww.metauid == key).First().notemptycolumns)
                    {
                        foreach (FrameDLRObject item in l)
                        {
                            if (ComFunc.nvl(item.GetValue(c.column_name)) == "")
                            {
                                return new
                                {
                                    code = "failed",
                                    msg = $"子表{c.column_name}栏位不可为空",
                                };
                            }
                        }
                    }
                }
            }
            foreach (var key in d.Keys)
            {
                //从表数据集检核
                if (key == "_subs") continue;

                if (!column_names.Contains(key))
                {
                    return new
                    {
                        code = "failed",
                        msg = "数据栏位不匹配",
                    };
                }
                //数据类型检查
                if (column_int.Contains(key) && ComFunc.nvl(d.GetValue(key)) != "" && !IntStd.IsInt(d.GetValue(key)))
                {
                    return new
                    {
                        code = "failed",
                        msg = $"值({d.GetValue(key)})不是int类型",
                    };
                }
                if (column_numbric.Contains(key) && ComFunc.nvl(d.GetValue(key)) != "" && !DecimalStd.IsDecimal(d.GetValue(key)))
                {
                    return new
                    {
                        code = "failed",
                        msg = $"({d.GetValue(key)})不是numberic类型",
                    };
                }
                if (column_bit.Contains(key) && ComFunc.nvl(d.GetValue(key)) != "" && !BoolStd.IsBool(d.GetValue(key)))
                {
                    return new
                    {
                        code = "failed",
                        msg = $"({d.GetValue(key)})不是bit类型",
                    };
                }
                if (column_datetime.Contains(key) && ComFunc.nvl(d.GetValue(key)) != "" && !DateTimeStd.IsDateTime(d.GetValue(key)))
                {
                    return new
                    {
                        code = "failed",
                        msg = $"({d.GetValue(key)})不是datetime类型",
                    };
                }
                if (column_time.Contains(key) && ComFunc.nvl(d.GetValue(key)) != "" && !DateTimeStd.IsDateTime(d.GetValue(key), "HH:mm:ss"))
                {
                    return new
                    {
                        code = "failed",
                        msg = $"({d.GetValue(key)})不是time类型",
                    };
                }
                if (column_date_year_month.Contains(key) && ComFunc.nvl(d.GetValue(key)) != "" && !DateTimeStd.IsDateTime(d.GetValue(key), "yyyy-MM-dd") && !DateTimeStd.IsDateTime(d.GetValue(key), "yyyy-MM"))
                {
                    return new
                    {
                        code = "failed",
                        msg = $"({d.GetValue(key)})不是date_year_month类型",
                    };
                }
                if (column_date_year.Contains(key) && ComFunc.nvl(d.GetValue(key)) != "" && !DateTimeStd.IsDateTime(d.GetValue(key), "yyyy-MM-dd") && !DateTimeStd.IsDateTime(d.GetValue(key), "yyyy"))
                {
                    return new
                    {
                        code = "failed",
                        msg = $"({d.GetValue(key)})不是date_year类型",
                    };
                }
            }
        }
        //有logic unique设定的时候做检查
        if (logicuniquecolumns.Count > 0)
        {
            foreach (FrameDLRObject d in datalist)
            {
                FrameDLRObject w = FrameDLRObject.CreateInstance();
                FrameDLRObject _pk_op = FrameDLRObject.CreateInstance();
                _pk_op.SetValue("$neq", d.GetValue("_default_pk"));
                w.SetValue("_default_pk", _pk_op);

                foreach (var uc in logicuniquecolumns)
                {
                    if (ComFunc.nvl(d.GetValue(uc)) == "")
                    {
                        return new
                        {
                            code = "failed",
                            msg = "唯一键栏位不可为空",
                        };
                    }
                    w.SetValue(uc, d.GetValue(uc));
                }
                //如果为子表，则须带入_default_ref做唯一键判断
                if (!string.IsNullOrEmpty(info.MetaMainUID))
                {
                    if (ComFunc.nvl(d.GetValue("_default_ref")) != "")
                    {
                        w.SetValue("_default_ref", d.GetValue("_default_ref"));
                    }
                }
                FrameDLRObject express = FrameDLRObject.CreateInstance($@"{{
$acttype : 'Query',
$table:'{tablename}'
}}");
                express.SetValue("$where", w);
                if (DB.Excute(up, express).QueryTable.RowLength > 0)
                {
                    return new
                    {
                        code = "failed",
                        msg = "数据重复，不能继续进行操作",
                    };
                }
            }
        }
        //有pk设定的时候做检查，排除_default_pk
        if (pkcolumns.Count > 1)
        {
            foreach (FrameDLRObject d in datalist)
            {
                //pk栏位不可为空

                FrameDLRObject w = FrameDLRObject.CreateInstance();
                FrameDLRObject _pk_op = FrameDLRObject.CreateInstance();
                _pk_op.SetValue("$neq", d.GetValue("_default_pk"));
                w.SetValue("_default_pk", _pk_op);

                foreach (var pk in pkcolumns)
                {
                    if (pk == "_default_pk") continue;
                    if (ComFunc.nvl(d.GetValue(pk)) == "")
                    {
                        return new
                        {
                            code = "failed",
                            msg = "PK栏位不可为空",
                        };
                    }
                    w.SetValue(pk, d.GetValue(pk));
                }
                //如果为子表，则须带入_default_ref做唯一键判断
                if (!string.IsNullOrEmpty(info.MetaMainUID))
                {
                    if (ComFunc.nvl(d.GetValue("_default_ref")) != "")
                    {
                        w.SetValue("_default_ref", d.GetValue("_default_ref"));
                    }
                }
                FrameDLRObject express = FrameDLRObject.CreateInstance($@"{{
$acttype : 'Query',
$table:'{tablename}'
}}");
                express.SetValue("$where", w);
                if (DB.Excute(up, express).QueryTable.RowLength > 0)
                {
                    return new
                    {
                        code = "failed",
                        msg = "数据主键重复，不能继续进行操作",
                    };
                }
            }
        }
        foreach (FrameDLRObject item in datalist)
        {
            FrameDLRObject d = FrameDLRObject.CreateInstance();

            foreach (var cc in item.Keys)
            {
                if (cc == "_subs") continue;
                var dtype = ComFunc.nvl(columns.Where(cw => cw.MetaColumnName == cc).First().MetaDataType);
                d.SetValue(cc, convert2DBValue(item.GetValue(cc), dtype));
            }
            //增加操作者的信息
            d.SetValue("last_id", login_id);
            d.SetValue("last_ip", login_ip);
            d.SetValue("last_name", login_name);
            d.SetValue("last_time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            //按照pk进行更新
            FrameDLRObject w = FrameDLRObject.CreateInstance();
            w.SetValue("_default_pk", d.GetValue("_default_pk"));

            DB.QuickUpdate(up, tablename, d, w);

            //从表数据新增
            FrameDLRObject stmp = FrameDLRObject.CreateInstance(item.GetValue("_subs"));
            foreach (var sub in stmp.Keys)
            {
                var subdatalist = (IEnumerable<object>)stmp.GetValue(sub);
                var subtablename = sub_dic[sub];
                DB.QuickDelete(up, subtablename, new
                {
                    _default_ref = d.GetValue("_default_pk")
                });
                foreach (dynamic subitem in subdatalist)
                {
                    foreach (var subc in sub_columns.Where(subw => subw.metauid == sub).First().columns)
                    {
                        var subdobj = (FrameDLRObject)subitem;
                        subdobj.Remove("RowNumber");

                        if (subitem.GetValue(subc.MetaColumnName) != null)
                        {
                            subdobj.SetValue(subc.MetaColumnName, convert2DBValue(subitem.GetValue(subc.MetaColumnName), subc.MetaColumnName));
                        }
                    }

                    subitem._status = MetaStatus.Save;
                    subitem._active = 0;
                    subitem._lock = MetaLock.UnLock;
                    subitem._is_deleted = 0;
                    subitem.add_id = login_id;
                    subitem.add_ip = login_ip;
                    subitem.add_name = login_name;
                    subitem.add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    subitem.last_id = login_id;
                    subitem.last_ip = login_ip;
                    subitem.last_name = login_name;
                    subitem.last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    subitem._default_ref = d.GetValue("_default_pk");

                    DB.QuickInsert(up, subtablename, subitem);
                }
            }
        }
        return new
        {
            code = "success",
            msg = $"操作成功",
        };
    }
    #endregion
}
}
